#pragma once

#include "requestor.hpp"
namespace RPC_project
{
    namespace client
    {
        class RpcCaller
        {
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponce = std::future<Json::Value>;
            using JsonResponseCallback = std::function<void(const Json::Value &)>;
            RpcCaller(const Requestor::ptr &requestor) : _requestor(requestor)
            {
            }

            // 用户进行同步调用,
            // 组织一个rpcrequest ，用_requestor发送 ,等待拿到response 设置并输出返回结果Json::Value &result
            bool call(const BaseConnection::ptr &conn, const std::string &method, const Json::Value params, Json::Value &result)
            {
                DLOG("开始同步RPC调用");
                // 1.组织请求
                BaseMessage::ptr base_ptr = MessageFactory::Create(MType::REQ_RPC);
                RpcRequest::ptr req_ptr = std::dynamic_pointer_cast<RPC_project::RpcRequest>(base_ptr);
                req_ptr->Setid(UUID::uuid());
                req_ptr->SetMyType(MType::REQ_RPC);
                req_ptr->SetMethod(method);
                req_ptr->SetParams(params);

                BaseMessage::ptr rsp;
                // 2. 通过_requestor发送请求
                bool ret = _requestor->sync_send(conn, std::dynamic_pointer_cast<RPC_project::BaseMessage>(req_ptr), rsp);
                if (ret == false)
                {
                    ELOG("同步请求失败");
                    return false;
                }
                DLOG("收到响应,进行解析 获取结果");
                // 3.等待拿到response
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(rsp);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应,向下类型转换失败！");
                    return false;
                }
                if (rpc_rsp_msg->Rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc请求出错: %s", errReason(rpc_rsp_msg->Rcode()).c_str());
                    return false;
                }
                result = rpc_rsp_msg->Result();
                //DLOG("结果设置完毕");

                return true;
            }

            // 用户进行异步调用
            // 向服务器发送异步回调请求，设置回调函数，回调函数中会传⼊⼀个promise对象， 在回调函数中去对promise设置数据
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value params, std::future<Json::Value> &result)
            {
                // 1.组织request
                BaseMessage::ptr base_ptr = MessageFactory::Create(MType::REQ_RPC);
                RpcRequest::ptr req_ptr = std::dynamic_pointer_cast<RPC_project::RpcRequest>(base_ptr);
                req_ptr->Setid(UUID::uuid());
                req_ptr->SetMyType(MType::REQ_RPC);
                req_ptr->SetMethod(method);
                req_ptr->SetParams(params);

                // 用户获取result  json_promise不能用局部变量 ,局部变量在call函数return后 ,result也就拿不到了,用智能指针
                auto json_promise = std::make_shared<std::promise<Json::Value>>();
                result = json_promise->get_future();
                // 智能指针,在仿函数进行构造的时候(传对象不传引用),内部会把智能指针对象保存一份 ,引用计数++,call return后,仿函数内部不释放 智能指针就释放不了

                Requestor::RequestCallback cb = std::bind(&RpcCaller::Callback, this, json_promise, std::placeholders::_1);
                // 2. 通过_requestor发送请求
                bool ret = _requestor->send(conn, req_ptr, cb);
                if (ret == false)
                {
                    ELOG("异步Rpc请求失败");
                    return false;
                }
                return true;
            }


            // 用户在rpc_caller中的JsonResponseCallback回调函数是针对RpcResponse中的result处理的
            // requestor中的send中的回调是针对BaseMessage处理的
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                         const Json::Value params, const JsonResponseCallback &cb)
            {
                // 1.组织请求
                BaseMessage::ptr base_ptr = MessageFactory::Create(MType::REQ_RPC);
                RpcRequest::ptr req_ptr = std::dynamic_pointer_cast<RPC_project::RpcRequest>(base_ptr);
                req_ptr->Setid(UUID::uuid());
                req_ptr->SetMyType(MType::REQ_RPC);
                req_ptr->SetMethod(method);
                req_ptr->SetParams(params);

                Requestor::RequestCallback req_cb = std::bind(&RpcCaller::Callback1, this, cb, std::placeholders::_1);
                bool ret = _requestor->send(conn, req_ptr, req_cb);
                if (ret == false)
                {
                    ELOG("回调RPC请求失败");
                    return false;
                }
                return true;
            }

        private:
            void Callback1(const JsonResponseCallback &cb, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应,向下类型转换失败！");
                    return;
                }
                if (rpc_rsp_msg->Rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc回调请求出错: %s", errReason(rpc_rsp_msg->Rcode()).c_str());
                    return;
                }
                cb(rpc_rsp_msg->Result());
            }

            void Callback(std::shared_ptr<std::promise<Json::Value>> result, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应 ,向下类型转换失败！");
                    return;
                }
                if (rpc_rsp_msg->Rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc异步请求出错:%s", errReason(rpc_rsp_msg->Rcode()).c_str());
                    return;
                }
                result->set_value(rpc_rsp_msg->Result());
               // DLOG("已设置promise的值");
            }

        private: 
            Requestor::ptr _requestor;
        };
    }
}